// Credits to http://www.blitzbasic.com/Community/posts.php?topic=42657
#include <math.h>

class Vector;
class Line;
class Plane;
class Matrix;
class Transform;


const float EPSILON=.000001f;		//small value
const float INFINITY=10000000.0f;	//big value

class Vector{
public:
	float x,y,z;

	Vector():x(0),y(0),z(0){
	}
	Vector( float x,float y,float z ):x(x),y(y),z(z){
	}
	operator float*(){
		return &x;
	}
	operator const float *(){
		return &x;
	}
	float &operator[]( int n ){
		return (&x)[n]; 
	}
	float operator[]( int n )const{
		return (&x)[n]; 
	}
	Vector operator-()const{
		return Vector( -x,-y,-z ); 
	}
	Vector operator*( float scale )const{
		return Vector( x*scale,y*scale,z*scale );
	}
	Vector operator*( const Vector &q )const{
		return Vector( x*q.x,y*q.y,z*q.z );
	}
	Vector operator/( float scale )const{
		return Vector( x/scale,y/scale,z/scale );
	}
	Vector operator/( const Vector &q )const{
		return Vector( x/q.x,y/q.y,z/q.z );
	}
	Vector operator+( const Vector &q )const{
		return Vector( x+q.x,y+q.y,z+q.z );
	}
	Vector operator-( const Vector &q )const{
		return Vector( x-q.x,y-q.y,z-q.z );
	}
	Vector &operator*=( float scale ){
		x*=scale;y*=scale;z*=scale;return *this;
	}
	Vector &operator*=( const Vector &q ){
		x*=q.x;y*=q.y;z*=q.z;return *this;
	}
	Vector &operator/=( float scale ){
		x/=scale;y/=scale;z/=scale;return *this;
	}
	Vector &operator/=( const Vector &q ){
		x/=q.x;y/=q.y;z/=q.z;return *this;
	}
	Vector &operator+=( const Vector &q ){
		x+=q.x;y+=q.y;z+=q.z;return *this;
	}
	Vector &operator-=( const Vector &q ){
		x-=q.x;y-=q.y;z-=q.z;return *this;
	}
	bool operator<( const Vector &q )const{
		if( fabs(x-q.x)>EPSILON ) return x<q.x ? true : false;
		if( fabs(y-q.y)>EPSILON ) return y<q.y ? true : false;
		return fabs(z-q.z)>EPSILON && z<q.z;
	}
	bool operator==( const Vector &q )const{
		return fabs(x-q.x)<=EPSILON && fabs(y-q.y)<=EPSILON && fabs(z-q.z)<=EPSILON;
	}
	bool operator!=( const Vector &q )const{
		return fabs(x-q.x)>EPSILON || fabs(y-q.y)>EPSILON || fabs(z-q.z)>EPSILON;
	}
	float dot( const Vector &q )const{
		return x*q.x+y*q.y+z*q.z;
	}
	Vector cross( const Vector &q )const{
		return Vector( y*q.z-z*q.y,z*q.x-x*q.z,x*q.y-y*q.x );
	}
	float length()const{
		return sqrtf(x*x+y*y+z*z);
	}
	float distance( const Vector &q )const{
		float dx=x-q.x,dy=y-q.y,dz=z-q.z;return sqrtf(dx*dx+dy*dy+dz*dz);
	}
	Vector normalized()const{
		float l=length();return Vector( x/l,y/l,z/l );
	}
	void normalize(){
		float l=length();x/=l;y/=l;z/=l;
	}
	float yaw()const{
		return -atan2f( x,z );
	}
	float pitch()const{
		return -atan2f( y,sqrtf( x*x+z*z ) );
	}
	void clear(){
		x=y=z=0;
	}
};
